import java.net.URL;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
 * Created by IntelliJ IDEA.
 * User: asd
 * Date: 07.okt.2010
 * Time: 14:31:18
 * Programmet bruker Standard DOM som parsingsteknikk.
 * Programeksempelet viser hvordan man kan ta tak i en RSS-kilde og traversere innholdet i denne basert p� DOM-parsing
 */

public class RSSReaderDOM {

  private static RSSReaderDOM instance = null;

  /**
   * Privat konstrukt�r. Dette er gjort for � sikre at det ikke opprettes flere instanser av samme objekt
   * i et program. Objekter av denne typen opprettes via getInstance()-metoden som er statisk og sikrer
   * at det kun forekommer en instans.
   * <p/>
   * Prinsipp: Singelton-pattern
   */
  public RSSReaderDOM() {
  }

  /**
   * Oppretter en ny instans av RSSReader forutsatt at det ikke allerede forekommer en instans av denne typen
   * i programmet. Metoden sikrer Singelton-pattern.
   *
   * @return Singelton instans av RSSReader-objekt
   */
  public static RSSReaderDOM getInstance() {
    if (instance == null) {
      instance = new RSSReaderDOM();
    }
    return instance;
  }

  /**
   * Henter ut "�verste" niv� av en nyhet ihht. RSS (item), og tar deretter og henter ut de enkelte
   * delene av RSS-str�mmen med henblikk p� en rekke spesifikke tags som man finner i RSS.
   * <p/>
   * Resultatet skrives ut til System.out (skjerm).
   */
  public void writeNews(String url) {
    try {

      // Lager dokumentet som skal parses
      DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
      URL u = new URL(url);
      Document doc = builder.parse(u.openStream());

      // Henter ut lista over "overordnete" items
      NodeList nodes = doc.getElementsByTagName("item");

      // og traverserer lista for � hente ut informasjon fra RSS-feeden
      for (int i = 0; i < nodes.getLength(); i++) {

        Element element = (Element) nodes.item(i);
        System.out.println("Tittel:" + getElementValue(element, "title"));
        System.out.println("Link:" + getElementValue(element, "link"));
        System.out.println("Publiseringsdato:" + getElementValue(element, "pubDate"));
        System.out.println("Ingress:" + getElementValue(element, "description"));
        System.out.println();
      }//for
    }//try
    catch (Exception ex) {
      doErrorMessage(ex);
    }

  }

    public ArrayList<News> getNews(String url)
    {
        String title, link, pubDate, desc;
        ArrayList<News> listOfNews = new ArrayList<News>();
        try {

      // Lager dokumentet som skal parses
      DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
      URL u = new URL(url);
      Document doc = builder.parse(u.openStream());

      // Henter ut lista over "overordnete" items
      NodeList nodes = doc.getElementsByTagName("item");

      // og traverserer lista for � hente ut informasjon fra RSS-feeden
      for (int i = 0; i < nodes.getLength(); i++) {

        Element element = (Element) nodes.item(i);
        title = getElementValue(element, "title");
        link =  getElementValue(element, "link");
        pubDate = getElementValue(element, "pubDate");
        desc = getElementValue(element, "description");
        listOfNews.add(new News(link, title, desc, pubDate));
      }//for
    }//try
    catch (Exception ex) {
      doErrorMessage(ex);
    }
      return listOfNews;
    }

  /**
   * Parser en del av RSS-feeden basert paa xml-innholdet slik det er definert i RSS mellom en start/slutt-tag
   * Brukes for aa hente ut en forekomst av en linje innenfor
   * @param parent Angir en forekomst av en start/slutt-tag
   * @param label Angir forekomst av element under en start/slutt-tag
   * @return Innholdet av angitt label                                             */
  protected String getElementValue(Element parent, String label) {
    return getCharacterDataFromElement((Element) parent.getElementsByTagName(label).item(0));
  }

  /**
   * Tar innholdet definert innenfor en start/slutt-tag og tolker dette som en streng.
   * @param e Innholdet innenfor en start/slutt-tag
   * @return Innhold tolket som streng
   */
  private String getCharacterDataFromElement(Element e) {
    try {
      Node child = e.getFirstChild();
      if (child instanceof CharacterData) {
        CharacterData cd = (CharacterData) child;
        return cd.getData();
      }
    }
    // Antar at siden XML-dokumentet er strukturert p� en ordentlig m�te (siden man har DOM-parsing) at
    // exceptions ikke vil kunne skje. Av denne grunn ingen h�ndtering av exception, kun en "placeholder" som
    // m� v�re der for � kunne kompilere. Kallet til doErrorMessage() skal aldri kunne skje, men er lagt inn for �
    // h�ndtere situasjoner som enn� ikke er kjent
    catch (Exception ex) {
      // OBS! Nullpointerexceptions vil kunne skje fra getFirstChild() uten at dette er feil.
      if (!(ex.getClass().equals(java.lang.NullPointerException.class)))
        doErrorMessage(ex);
    }
    return "";
  }

  /**
   * Feilmelding til konsoll
   * @param e Exception
   */
  private void doErrorMessage(Exception e) {
    System.out.println("========================================================");
    System.out.println("= ClassName: " + this.getClass().getName());
    System.out.println("= Exception: " + e.getClass().getName());
    System.out.println(
        "= -----------------------------------------------------");
    System.out.println("= Message  : " + e.getMessage());
    System.out.println("= Cause    : " + e.getClass());
    System.out.println("========================================================");
    System.out.println("= StackTrace:");
    e.printStackTrace(System.out);
  }


  /**
   * Et meget enkelt hovedprogram ...
   * @param args
   */
  /*
  public static void main(String[] args) {
    RSSReaderDOM reader = RSSReaderDOM.getInstance();
    reader.writeNews("http://www.vg.no/rss/create.php?categories=10,12");
  } */
}
